import { Graph, Shape, Addon, FunctionExt } from '@antv/x6'
import { initRegisterNodes, ModelRect } from './nodes'
import initRegisterEdges from './edges'
import { items } from './items'
import EventBus from '../EventBus'
import BusEvents from '../EventBus/events'

// 为 Graph 全局注册 Node 和 Edge
initRegisterNodes()
initRegisterEdges()

const { Stencil, Dnd } = Addon
const { Circle, Rect } = Shape

class X6Editor {
  graph = null
  dnd = null
  constructor(container, stencilContainer, minimapContainer) {
    this.init(container, minimapContainer)
    // this.initStencil(stencilContainer)
    this.initDnd()
    this.initEvents()
  }

  init(container, minimapContainer) {
    const graph = (this.graph = new Graph({
      container: container,
      autoResize: true,
      // 绘制网格
      grid: {
        size: 10,
        visible: true,
        type: 'mesh',
        args: {
          color: '#e0e0e0',
          thickness: 1,
        },
      },
      // 背景
      background: {
        color: '#eeeeee',
        // image: require('../../../assets/logo.svg'),
        image:
          'https://gw.alipayobjects.com/os/s/prod/antv/assets/image/logo-with-text-73b8a.svg',
        position: 'center',
        size: {
          width: 400,
          height: 300,
        },
        repeat: 'repeat',
        opacity: 0.1,
      },
      // 对齐线
      snapline: true,
      // 滚动画布
      scroller: {
        enabled: true,
        pannable: true,
      },
      // 小地图
      minimap: {
        enabled: true,
        container: minimapContainer,
        width: 240,
        height: 160,
      },
      // 撤销、重做
      history: true,
      // 剪切板
      clipboard: true,
      // 键盘快捷键
      keyboard: {
        enabled: true,
        global: true
      },
      // 鼠标滚轮缩放
      mousewheel: {
        enabled: true,
        modifiers: ['ctrl'],
      },
      // 点选、框选
      selecting: {
        enabled: true,
        multiple: true,
        rubberband: true,
        modifiers: ['alt'],
        movable: true,
      },
      // 旋转节点
      rotating: false,
      // 缩放节点
      resizing: false,
      // 平移节点
      translating: {
        restrict: false,
      },
      // 平移缩放节点的基础选项
      transforming: {
        clearAll: true,
        clearOnBlankMouseDown: true,
      },
      // 嵌套节点
      embedding: {
        enabled: true,
        findParent: 'bbox',
        frontOnly: true,
      },
      // 连线选项
      connecting: {
        snap: {
          radius: 50,
        },
        allowBlank: false,
        allowMulti: 'withPort',
        allowLoop: false,
        allowNode: false,
        allowEdge: false,
        allowPort: true,
        highlight: true,
        connector: 'rounded',
        connectionPoint: 'boundary',
        router: {
          name: 'er',
          args: {
            direction: 'V',
          },
        },
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: '#a0a0a0',
                strokeWidth: 1,
                targetMarker: {
                  name: 'classic',
                  size: 7,
                },
              },
            },
          })
        },
        validateConnection({ sourceView, targetView, targetMagnet }) {
          if (!targetMagnet) {
            return false
          }
          if (targetMagnet.getAttribute('port-group') !== 'in') {
            return false
          }
          if (targetView) {
            const node = targetView.ceil
            if (node) {
              const portId = targetMagnet.getAttribute('port')
              const usedInPorts = node.getUsedInPorts(graph)
              if (usedInPorts.find((port) => port && port.id === portId)) {
                return false
              }
            }
          }
          return true
        },
      },
      // 高亮选项
      highlighting: {
        magnetAvailable: {
          name: 'stroke',
          args: {
            padding: 4,
            attrs: {
              'stroke-width': 2,
              stroke: 'red',
            },
          },
        },
        magnetAdsorbed: {
          name: 'stroke',
          args: {
            attrs: {
              fill: '#fff',
              stroke: '#31d0c6',
            },
          },
        },
      },
    }))

    // window.addEventListener('resize', () => {
    //   const container = graph.container
    //   const width = container.clientWidth
    //   const height = container.clientHeight
    //   graph.resize(width, height)
    //   graph.centerContent()
    // })
  }

  initStencil(stencilContainer) {
    const stencil = new Stencil({
      title: 'Components',
      target: this.graph,
      search(cell, keyword) {
        return cell.label.toLowerCase().indexOf(keyword.toLowerCase()) !== -1
      },
      placeholder: 'Search ...',
      notFoundText: 'Not Found',
      collapsable: true,
      stencilGraphWidth: 300,
      stencilGraphHeight: 180,
      groups: [
        {
          name: 'basic',
          title: 'Basic Components',
          graphHeight: 500,
          layoutOptions: {
            columns: 1,
            marginX: 60,
          },
        },
        {
          name: 'other',
          title: 'Other Components',
          collapsable: true,
          collapsed: true,
          graphHeight: 500,
          layoutOptions: {
            columns: 1,
            marginX: 60,
          },
        },
      ],
    })

    stencilContainer.appendChild(stencil.container)

    // 添加图元
    items.forEach((item) => {
      const title = item.title
      const elements = item.elements.map((element) => {
        let portItems = []
        Object.keys(element.ports).forEach((key) => {
          element.ports[key].forEach((aPortOfKey) => {
            if (typeof aPortOfKey === 'string') {
              let portItem = {
                id: aPortOfKey,
                group: key,
                attrs: {
                  text: {
                    text: aPortOfKey,
                  },
                },
              }
              portItems.push(portItem)
            }
          })
        })

        return new ModelRect({
          label: element.label,
          ports: {
            items: portItems,
          },
        })
      })

      stencil.load(elements, title)
    })
  }

  initDnd() {
    const { graph } = this
    this.dnd = new Dnd({ target: graph, animation: true, validateNode: validate, getDropNode: getDropNode })

    function validate() {
      return true
    }
    function getDropNode(node) {
      return node.clone()
    }
  }

  initEvents() {
    const { graph } = this
    const container = graph.container

    // 节点事件
    graph.on('node:mouseenter', FunctionExt.debounce(() => {
        const ports = container.querySelectorAll('.x6-port-body')
        const texts = container.querySelectorAll('.x6-port-label')
        showPorts(ports, true)
        showPorts(texts, true)
      })
    )
    graph.on('node:mouseleave', FunctionExt.debounce(() => {
        const ports = container.querySelectorAll('.x6-port-body')
        const texts = container.querySelectorAll('.x6-port-label')
        showPorts(ports, false)
        showPorts(texts, false)
      })
    )
    graph.on('node:dblclick', (node) => {
      EventBus.$emit(BusEvents.NodeDBLCLick, { node: node.node })
    })
    // 选中节点变化事件
    graph.on('selection:changed', ({ added, removed }) => {
      added.forEach((cell) => {
        if (cell.isNode()) {
          cell.attr('body', {
            stroke: '#ffa940',
          })
        } 
        // 不处理边的样式
        // else {
        //   cell.attr('line/stroke', '#ffa940')
        // }
      })
      removed.forEach((cell) => {
        if (cell.isNode()) {
          cell.attr('body', {
            stroke: '#108ee9'
          })
        } 
        // 不处理边的样式
        // else {
        //   cell.attr('line/stroke', '#dddddd')
        // }
      })
    })

    // 绑定键盘事件
    graph.bindKey('ctrl+z', () => {
      EventBus.$emit(BusEvents.CommandUndo)
    })
    graph.bindKey('ctrl+shift+z', () => {
      EventBus.$emit(BusEvents.CommandRedo)
    })
    graph.bindKey('ctrl+c', () => {
      EventBus.$emit(BusEvents.CommandCopy)
    })
    graph.bindKey('ctrl+v', () => {
      EventBus.$emit(BusEvents.CommandPaste)
    })
    graph.bindKey('ctrl+x', () => {
      EventBus.$emit(BusEvents.CommandCut)
    })
    graph.bindKey('delete', () => {
      EventBus.$emit(BusEvents.CommandDelete)
    })
    graph.bindKey('ctrl+p', () => {
      EventBus.$emit(BusEvents.CommandDownload)
    })
  }

  close() {
    // const { graph } = this
    // window.removeEventListener('resize', () => {
    //   const container = graph.container
    //   const width = container.clientWidth
    //   const height = container.clientHeight
    //   graph.resize(width, height)
    //   graph.centerContent()
    // })
  }
}

/**
 * ports或者texts是否可见
 * @param {Array} ports
 * @param {boolean} visible
 */
function showPorts(ports, visible) {
  ports.forEach((port) => {
    port.style.visibility = visible ? 'visible' : 'hidden'
  })
}

export { X6Editor }
